export const randomArrayBuffer = length => new Promise((resolve, reject) => {
    //  #ifdef MP-WEIXIN
    wx.getRandomValues({ length, success: res => resolve(res.randomValues), fail: reject })
    // #endif

    // #ifndef MP-WEIXIN
    try {
        resolve(crypto.getRandomValues(new Uint8Array(length)))
    } catch (error) {
        reject(error)
    }
    // #endif
})

/*
 * 自定义字母表
 * 
 */
export const customAlphabet = (alphabet, defaultSize = 21, getRandom = randomArrayBuffer) => {
    // 这是为了得出能表示字符表长度的最大数值（0b10左移N位再-1，二进制表示就是全1的）。
    // 比如文中提到的30，二进制表示是0b11110，那最大能包括它的是（0b10左移4位再-1）0b11111，也就是2^5-1，即31
    let mask = (2 << (Math.log(alphabet.length - 1) / Math.LN2)) - 1
    let step = -~((1.6 * mask * defaultSize) / alphabet.length)
    return async (size = defaultSize) => {
        let id = ''
        while (true) {
            let bytes =  new Uint8Array(await getRandom(step))
            let j = step
            while (j--) {
                id += alphabet[bytes[j] & mask] || ''
                if (id.length === size) return id
            }
        }
    }
}

/*
 * NanoID算法
 * 
 */
export const nanoId = async (length = 21) => {
    return (new Uint8Array(await randomArrayBuffer(length))).reduce((id, byte) => {
        byte &= 63
        if (byte < 36) id += byte.toString(36)
        else if (byte < 62) id += (byte - 26).toString(36).toUpperCase()
        else if (byte > 62) id += '-'
        else id += '_'
        return id
    }, '')
}

export default nanoId
